#include <windows.h>
#include <math.h>
#include "MYSQL/mysql.h"

#include "CDb.h"
#include "CConsole.h"
#include "CGuildShop.h"
#include "ItemTypes/CShopItem.h"

CGuildShop::CGuildShop(unsigned short guildID) : CItemContainer(0xFF, NULL) {  // Container location none, owner null
	setId(guildID);
	m_currPriceList = NULL;
	m_currSellList = NULL;
	m_showInBuyMenu = NULL;

	loadSQL();
}

CGuildShop::~CGuildShop() {
}

void CGuildShop::setId(unsigned short id) {
	m_id = id;
}

unsigned short CGuildShop::getId() {
	return m_id;
}

void CGuildShop::loadSQL() {
	MYSQL_RES * res;
	MYSQL_ROW row;
	char query[8192];
	sprintf(query, "SELECT `itemID`, `quantity`, `max`, `min_price`, `max_price`, `daily_increase` FROM guild_shops WHERE guildID = %i", getId());
	int count = (int)strlen(query);

	MYSQL* mysqlConn=CDb::getConn(); //get conn
	mysql_real_query(mysqlConn, query, count);
	res = mysql_store_result(mysqlConn);
	CDb::pushConn(mysqlConn); //release conn

	if(!res) {
		CConsole::outDebOnly("Error looking up guild shop ID %i.", getId());
	} 
	else if(mysql_num_rows(res))
	{
		setGuildSize((unsigned char)mysql_num_rows(res));
		unsigned short itemID;
		unsigned long quantity;
		unsigned char maxQuantity;
		unsigned char slotID;
		unsigned long minprice;
		unsigned long maxprice;
		unsigned char dailyIncrease; 
		unsigned char size = 0;
		CShopItem* item;
		while(row = mysql_fetch_row(res)) 
		{
			itemID = (unsigned short)atoi(row[0]);
			slotID = getItemSlotId(itemID);
			if(slotID == 0xFF) 
			{
				quantity = (unsigned long)atoi(row[1]);
				maxQuantity = (unsigned char)atoi(row[2]);
				minprice = (unsigned long)atoi(row[3]);
				maxprice = (unsigned long)atoi(row[4]);
				dailyIncrease = (unsigned char)atoi(row[4]);

				item = new CShopItem();//createItem(itemID);
				item->setId(itemID);
				item->setStackSize(maxQuantity);
				item->setMaxQuantity(maxQuantity);
				item->setQuantity(quantity);
				item->setDailyIncrease(dailyIncrease);
				item->setMinPrice(minprice);
				item->setMaxPrice(maxprice);

				// Increase container size by 1
				size += 1;
				
				// Put item into new slot in container
				setItem(size, item);
				item->setShopSlot(size);
			} 
			else 
			{
				CConsole::outErr("Item %i already exists in guild shop %i",itemID, getId());
			}
		}
		if (size!=mysql_num_rows(res))
		{
			CConsole::outErr("Guild shop %i contains less items than there were rows in the db. Rows: %d - Unique Items: %d!", mysql_num_rows(res), size);
			setGuildSize(size);
		}
		mysql_free_result(res);
	}
	updatePrices();
}

unsigned char CGuildShop::getItemSlotId(unsigned short itemID) {
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) {
		CItem * item = getItem(slotID);
		if(item != NULL)
			if(item->getId() == itemID)
				return slotID;
	}
	return 0xFF;
}

void CGuildShop::setGuildSize(unsigned char size) {
	if(size == 0)
		return;
	if(size <= getSize()) {
		CConsole::outDebOnly("Size is smaller or equal to current container size.");
		return;
	}
	// Create temporary new list of new bigger size
	bool * newShowInBuyMenu = NULL;
	unsigned long * newCurrPriceList = NULL;
	unsigned long * newCurrSellList = NULL;

	newShowInBuyMenu = new bool[size];
	newCurrPriceList = new unsigned long[size];
	newCurrSellList = new unsigned long[size];

	memset( newShowInBuyMenu, 0, size * sizeof(bool) );
	memset( newCurrPriceList, 0, size * sizeof(unsigned long) );
	memset( newCurrSellList, 0, size * sizeof(unsigned long) );

	if(m_showInBuyMenu != NULL) {
		// Copy the items onto the new list
		memcpy( newShowInBuyMenu, m_showInBuyMenu, getSize() * sizeof(bool) );

		// Delete old list from memory
		delete [] m_showInBuyMenu;
	}
	if(m_currPriceList != NULL) {
		// Copy the items onto the new list
		memcpy( newCurrPriceList, m_currPriceList, getSize() * sizeof(unsigned long) );

		// Delete old list from memory
		delete [] m_currPriceList;
	}
	if(m_currSellList != NULL) {
		// Copy the items onto the new list
		memcpy( newCurrSellList, m_currSellList, getSize() * sizeof(unsigned long) );

		// Delete old list from memory
		delete [] m_currSellList;
	}

	// Set itemList to new bigger list
	m_showInBuyMenu = newShowInBuyMenu;
	m_currPriceList = newCurrPriceList;
	m_currSellList = newCurrSellList;
	setSize(size);
}

void CGuildShop::setPrice(CItem* item, unsigned char slotID, unsigned long price) 
{
	m_currPriceList[slotID-1] = price;

	//imho we shouldn't store those in the db! -- greetz Dantalion
	/*
	char query[8192];
	sprintf(query, "UPDATE guild_shops SET curr_price = %i WHERE guildID = %i AND itemID = %i",price, this->getId(), item->getId());
	int count = (int)strlen(query);
	MYSQL * mysqlConn=CDb::getConn(); //get conn
	mysql_real_query(mysqlConn, query, count);
	CDb::pushConn(mysqlConn); //release conn
	*/
}

void CGuildShop::setSellPrice(CItem* item, unsigned char slotID, unsigned long price) 
{
	m_currSellList[slotID-1] = price;

	//imho we shouldn't store those in the db! -- greetz Dantalion
	/*
	char query[8192];
	sprintf(query, "UPDATE guild_shops SET curr_sellprice = %i WHERE guildID = %i AND itemID = %i",price, this->getId(), item->getId());
	int count = (int)strlen(query);
	MYSQL * mysqlConn=CDb::getConn(); //get conn
	mysql_real_query(mysqlConn, query, count);
	CDb::pushConn(mysqlConn); //release conn
	*/
}

unsigned long CGuildShop::getPrice(unsigned short itemID) {
	unsigned char slotID = 0x00;
	slotID = getItemSlotId(itemID);
	if(slotID != 0xFF) {
		return m_currPriceList[slotID-1];
	} else {
		CConsole::outDebOnly("Cannot get price.  Item %i not found in guild shop.",itemID);
	}
	return 0;
}

unsigned long CGuildShop::getSellPrice(unsigned short itemID) {
	unsigned char slotID = 0x00;
	slotID = getItemSlotId(itemID);
	if(slotID != 0xFF) {
		return m_currSellList[slotID-1];
	} else {
		CConsole::outDebOnly("Cannot get sell price.  Item %i not found in guild shop.",itemID);
	}
	return 0;
}

void CGuildShop::updatePrices() 
{
	CShopItem* item = NULL;
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) 
	{
		item = (CShopItem*)getItem(slotID);
		if (item==NULL)
			continue;
		
		unsigned short itemID = item->getId();

		//Calculate max
		unsigned int max = (int)ceil( (float)item->getMaxQuantity() * 3 / 4 );
		max %= 61;

		unsigned long quantity = item->getQuantity();

		// Update prices
		unsigned long curr_price;
		if(quantity < max) 
		{
			curr_price = (unsigned long)( (float)(item->getMaxPrice() - item->getMinPrice()) * (max - quantity) / max );
			curr_price += item->getMinPrice();
		} 
		else 
			curr_price = item->getMinPrice();

		setPrice(item, slotID, curr_price);

		// Update selling prices
		unsigned long sellPrice = item->getSellPrice();
		unsigned long curr_sellPrice;
		if(quantity < max) {
			curr_sellPrice = (unsigned long)( (float)(sellPrice / 2) * (max - quantity) / max );
			curr_sellPrice += sellPrice;
		} else 
			curr_sellPrice = sellPrice;

		setSellPrice(item, slotID, curr_sellPrice);
	}
}

void CGuildShop::restock() 
{
	CShopItem* item = NULL;
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) 
	{
		item = (CShopItem*)getItem(slotID);

		if (item==NULL)
			continue;

		unsigned short itemID = item->getId();

		//Calculate new Quantity
		unsigned long newQuantity = item->getQuantity()+item->getDailyIncrease();
		newQuantity%=151; // quantity caps at 150
		newQuantity%=(int)ceil( (float)item->getMaxQuantity() * 3 / 4 ); //Quantity caps at 3/4 the max to allow sellback

		item->setQuantity(newQuantity);

		if(newQuantity > 0)
			itemIsInBuyMenu(item, true);
		else
			itemIsInBuyMenu(item, false);
	}
}

void CGuildShop::itemIsInBuyMenu(CShopItem* item, bool isInBuyMenu) 
{ 
	m_showInBuyMenu[item->getShopSlot()-1] = isInBuyMenu;
}

bool CGuildShop::itemIsInBuyMenu(unsigned short itemID) {
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) {
		CItem * item = NULL;
		item = getItem(slotID);
		if(item != NULL) {
			if(item->getId() == itemID) {
				return m_showInBuyMenu[slotID-1];
			}
		}
	}
	return false;
}

void CGuildShop::addQuantity(unsigned short itemID, unsigned char quantity) 
{
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) 
	{
		CShopItem * item = NULL;
		item = (CShopItem*)getItem(slotID);
		if(item != NULL) {
			if(item->getId() == itemID) {
				unsigned char max = item->getStackSize();
				unsigned char itemQty = (unsigned char)item->getQuantity();
				unsigned char qtyRemain = 0;
				qtyRemain = max - itemQty;
				if(quantity >= qtyRemain) {
					itemQty = max;
					item->setQuantity(itemQty);
				} else {
					itemQty += quantity;
					item->setQuantity(itemQty);
				}
				itemIsInBuyMenu(item, true);

				char query[8192];
				sprintf(query, "UPDATE guild_shops SET quantity = %i WHERE guildID = %i AND itemID = %i",itemQty, getId(), itemID);
				int count = (int)strlen(query);
				MYSQL * mysqlConn=CDb::getConn(); //get conn
				mysql_real_query(mysqlConn, query, count);
				CDb::pushConn(mysqlConn); //release conn

				return;
			}
		}
	}
	CConsole::outDebOnly("Cannot add quantity.  Item not found in guild shop");
}

void CGuildShop::removeQuantity(unsigned short itemID, unsigned char quantity) {
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) {
		CItem * item = NULL;
		item = getItem(slotID);
		if(item != NULL) {
			if(item->getId() == itemID) {
				unsigned char itemQty = (unsigned char)item->getQuantity();
				if(quantity > itemQty)
					itemQty = 0;
				else
					itemQty -= quantity;
				item->setQuantity(itemQty);

				char query[8192];
				sprintf(query, "UPDATE guild_shops SET quantity = %i WHERE guildID = %i AND itemID = %i",itemQty, getId(), itemID);
				int count = (int)strlen(query);
				MYSQL * mysqlConn=CDb::getConn(); //get conn
				mysql_real_query(mysqlConn, query, count);
				CDb::pushConn(mysqlConn); //release conn

				return;
			}
		}
	}
	CConsole::outDebOnly("Cannot remove quantity.  Item not found in guild shop");
}

unsigned char CGuildShop::getMaxQuantity(unsigned short itemID) {
	for(unsigned char slotID = 1; slotID <= getSize(); slotID++) {
		CItem * item = NULL;
		item = getItem(slotID);
		if(item != NULL) {
			if(item->getId() == itemID) {
				return item->getStackSize();
			}
		}
	}
	return 0;
}